SpringBoot+Vue3前后端分离课程管理系统:从零搭建企业级全栈项目

📅 2026/7/28 19:01:52
SpringBoot+Vue3前后端分离课程管理系统:从零搭建企业级全栈项目
如果你正在寻找一个能跑通、能学习、能直接用于毕业设计或课程实践的完整项目那么基于 SpringBoot Vue3 前后端分离的课程管理系统很可能就是你需要的那个“样板工程”。但问题来了网上开源项目那么多为什么这个组合值得你投入时间它真的只是一个简单的 CRUD 演示还是能让你学到企业级开发的完整链路我的判断是这个项目真正的价值不在于它实现了“课程管理”这个业务本身而在于它完整地呈现了现代 Java Web 应用从技术选型、架构设计、前后端协作到安全与部署的标准范式。很多初学者学了一堆零散的 SpringBoot 注解和 Vue3 语法但一到整合阶段就卡壳跨域问题怎么解决JWT 怎么集成MyBatis-Plus 的分页查询怎么写这个项目恰好提供了一个经过验证的、可直接运行的答案。本文将带你从零开始深度拆解一个典型的 SpringBoot Vue3 前后端分离课程管理系统。我不会只给你代码和截图而是会重点讲清楚为什么选择这个技术栈每个技术组件在项目中扮演什么角色从环境搭建到功能实现有哪些必须绕开的“坑”无论你是想快速完成一个课程作业还是希望系统性地掌握全栈开发流程这篇文章都将提供一条清晰的路径。1. 项目核心价值为什么是 SpringBoot Vue3 前后端分离在深入代码之前我们必须先理解这个技术组合背后的逻辑。这决定了你是在“抄作业”还是在“学方法”。前后端分离架构是这个项目的基石。传统的 JSP、Thymeleaf 等模板引擎技术将前端页面和后端逻辑强耦合在一起。这带来几个明显问题前端工程师需要懂 Java 环境后端修改一点逻辑可能影响整个页面渲染项目难以并行开发。而前后端分离将前端Vue3 应用和后端SpringBoot API 服务彻底解耦两者通过 HTTP API通常是 RESTful 风格进行通信。前端专注于用户交互和界面渲染后端专注于业务逻辑和数据持久化。这种模式带来了开发效率、可维护性和技术栈灵活性的巨大提升。SpringBoot作为后端框架其核心优势是“约定大于配置”。它通过一系列 Starter 依赖和自动配置让你几乎不用编写繁琐的 XML 配置文件就能快速搭建一个生产就绪的 Web 应用。内嵌的 Tomcat 服务器让你可以直接通过一个可执行的 JAR 包来运行应用极大简化了部署。对于课程管理系统这类业务逻辑明确、需要快速迭代的项目SpringBoot 是效率最高的选择之一。Vue3作为前端框架相比于 Vue2它在性能基于 Proxy 的响应式系统、开发体验Composition API和 TypeScript 支持上都有显著提升。对于管理后台这类交互复杂、状态繁多的应用Vue3 的组合式 API 能让逻辑组织更清晰代码复用性更好。配合 Element Plus 等 UI 库可以快速搭建出美观且功能丰富的界面。MyBatis-Plus是一个强大的 MyBatis 增强工具它提供了通用的 Mapper 和 Service 实现让你无需编写简单的 CRUD SQL同时保留了 MyBatis 的灵活性。在项目中你会看到它如何极大地减少数据访问层的样板代码。所以这个项目组合的深层价值在于它是一套经过市场验证的、用于构建现代 Web 应用的最佳实践集合。通过完成它你不仅能学会单个技术更能掌握它们如何协同工作解决真实的工程问题。2. 系统功能与核心模块设计一个完整的课程管理系统其核心是围绕“课程”这一主体管理与之相关的“人”学生、教师、管理员和“事”作业、考试、成绩。根据提供的材料我们可以梳理出系统的核心功能模块用户权限管理实现学生、教师、管理员三种角色的注册、登录、认证与授权。不同角色拥有不同的操作权限如教师可发布课程学生只能选课学习。课程全生命周期管理包括课程的创建、发布、修改、状态管理未开始/进行中/已结束、以及学生的选课/退课。学习过程管理作业模块教师发布作业学生提交作业支持文本或文件教师批改并反馈。在线考试/测验模块教师组织考试学生在线答题系统自动或手动判分。成绩统计系统汇总作业、考试等成绩形成学生个人的成绩单或课程整体的成绩分析。数据统计与展示为管理员和教师提供数据看板如课程数量、学生活跃度、成绩分布等。从数据库设计上看系统至少包含以下几张核心表这直接反映了业务实体和它们之间的关系用户表 (user_info): 存储所有用户的基础信息。课程表 (course_info): 存储课程的核心信息。选课关系表 (student_course): 记录学生与课程的多对多关系。作业表 (homework) 与作业提交表 (homework_submission): 分别存储作业任务和学生提交记录。考试表 (exam) 与成绩表 (score): 管理考试和成绩。这种清晰的模块划分和数据库设计是保证项目可扩展、易维护的前提。在开发时我们通常会为每个核心模块创建对应的 Controller、Service、Mapper 和前端路由、页面组件。3. 开发环境与工具准备工欲善其事必先利其器。以下是搭建本项目开发环境所需的工具清单及简要说明。请注意版本号建议使用较新的稳定版但具体版本请根据项目源码的pom.xml和package.json进行调整。后端环境 (SpringBoot):JDK: 版本 8 或 11推荐 11长期支持版。确保JAVA_HOME环境变量配置正确。Maven: 版本 3.6用于管理项目依赖、构建和打包。IDE: IntelliJ IDEA (社区版或旗舰版) 或 Eclipse with STS。IDEA 对 SpringBoot 的支持更友好。数据库: MySQL 5.7 或 8.0。需要提前安装并创建好数据库如course_management。其他: 可能需要 Redis用于缓存或Session管理、Elasticsearch搜索等但基础版本可能不需要。前端环境 (Vue3):Node.js: 版本 16推荐 18 LTS。这是运行 JavaScript 和 npm 的基础。包管理器: npm 或 yarn。安装 Node.js 后自带 npm。Vue CLI 或 Vite: 现代 Vue 项目脚手架。Vite 启动更快是 Vue3 官方推荐。本文示例将使用 Vite。IDE: Visual Studio Code配合 Volar 插件Vue3 官方推荐扩展。第一步验证基础环境打开终端或命令提示符分别执行以下命令确认安装成功# 检查 Java java -version # 检查 Maven mvn -v # 检查 Node.js 和 npm node -v npm -v第二步获取项目源码你可以从开源平台如 Gitee, GitHub或提供的链接获取项目初始代码。通常是一个包含backend后端和frontend前端两个文件夹的工程或者两个独立的代码仓库。第三步初始化数据库使用 MySQL 客户端如命令行、Navicat、DBeaver连接你的 MySQL 服务执行项目提供的 SQL 脚本通常命名为schema.sql或init.sql来创建数据库和表结构。如果项目没有提供则需要根据实体类Entity或上文提到的表结构自行创建。4. 后端工程详解从启动类到控制器让我们深入后端 SpringBoot 项目的核心代码。理解这些代码你就掌握了 SpringBoot 应用的骨架。4.1 项目启动与配置一切始于启动类。这是一个标准的 SpringBoot 应用入口。// 文件路径src/main/java/com/course/management/CourseManagementApplication.java package com.course.management; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; SpringBootApplication // 核心注解开启组件扫描、自动配置等 MapperScan(basePackages {com.course.management.mapper}) // 扫描 MyBatis Mapper 接口 public class CourseManagementApplication extends SpringBootServletInitializer { public static void main(String[] args) { // 启动嵌入式 Tomcat 并运行 Spring 应用 SpringApplication.run(CourseManagementApplication.class, args); } Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { // 支持传统的 WAR 包部署到外部 Servlet 容器如 Tomcat return builder.sources(CourseManagementApplication.class); } }SpringBootApplication: 这是一个组合注解包含了Configuration,EnableAutoConfiguration,ComponentScan。它告诉 SpringBoot 从这里开始自动扫描当前包及其子包下的组件。MapperScan: 这是 MyBatis 的注解用于指定 MyBatis Mapper 接口所在的包路径。SpringBoot 会自动为这些接口创建代理实现类你无需编写实现。SpringBootServletInitializer: 继承这个类并重写configure方法是为了让应用可以打包成 WAR 文件部署到独立的外部 Tomcat 等 Servlet 容器中。如果只使用内嵌服务器运行 JAR这部分不是必须的。4.2 应用配置文件SpringBoot 的配置集中在application.properties或application.yml中。YAML 格式更清晰推荐使用。# 文件路径src/main/resources/application.yml server: port: 8080 # 服务器端口 servlet: context-path: /api # API 统一前缀方便前端代理 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/course_management?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai username: root password: your_password # 请替换为你的数据库密码 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台打印 SQL 日志调试用 global-config: db-config: id-type: auto # 主键策略数据库自增 mapper-locations: classpath:mapper/*.xml # MyBatis XML 映射文件位置 # JWT 配置示例如果项目使用了JWT jwt: secret: your_jwt_secret_key_here # 密钥务必复杂且保密 expire: 604800 # token 过期时间秒例如7天 header: Authorization关键配置解读server.servlet.context-path: 为所有后端 API 添加/api前缀。这样前端请求http://localhost:8080/api/user/login就能访问到后端。spring.datasource: 数据源配置连接你的 MySQL 数据库。注意时区设置serverTimezone避免时间错误。mybatis-plus.configuration.log-impl: 开发阶段非常有用可以在控制台看到 MyBatis 执行的 SQL 语句便于调试。jwt: 如果系统采用 Token 鉴权这是前后端分离的标配需要配置 JWT 的密钥和过期时间。4.3 核心控制器示例用户模块控制器Controller负责接收 HTTP 请求调用服务层处理业务并返回响应。以下是用户控制器的一个简化示例展示了登录、注册、查询等核心操作。// 文件路径src/main/java/com/course/management/controller/UserController.java package com.course.management.controller; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.course.management.common.Result; import com.course.management.entity.User; import com.course.management.service.UserService; import com.course.management.utils.JwtUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import java.util.HashMap; import java.util.Map; RestController RequestMapping(/user) // 映射到 /api/user 路径下 public class UserController { Autowired private UserService userService; Autowired private JwtUtil jwtUtil; /** * 用户登录 * param loginForm 包含 username 和 password 的登录表单 * return 登录结果和 Token */ PostMapping(/login) public Result login(RequestBody Valid LoginForm loginForm) { // 1. 验证用户名密码 User user userService.login(loginForm.getUsername(), loginForm.getPassword()); if (user null) { return Result.error(用户名或密码错误); } // 2. 生成 JWT Token MapString, Object claims new HashMap(); claims.put(userId, user.getId()); claims.put(username, user.getUsername()); claims.put(role, user.getRole()); String token jwtUtil.generateToken(claims); // 3. 返回用户基本信息排除密码和 Token MapString, Object data new HashMap(); data.put(user, userService.safeUserInfo(user)); // 一个移除敏感信息的方法 data.put(token, token); return Result.success(登录成功, data); } /** * 用户注册 */ PostMapping(/register) public Result register(RequestBody Valid RegisterForm registerForm) { // 检查用户名是否已存在 if (userService.findByUsername(registerForm.getUsername()) ! null) { return Result.error(用户名已存在); } User newUser userService.register(registerForm); return Result.success(注册成功, newUser.getId()); } /** * 获取当前用户信息需要 Token 认证 */ GetMapping(/info) public Result getCurrentUserInfo(HttpServletRequest request) { // 从请求头中获取 Token并解析出用户ID String token request.getHeader(jwtUtil.getHeader()); Long userId jwtUtil.getUserIdFromToken(token); User user userService.getById(userId); return Result.success(userService.safeUserInfo(user)); } /** * 分页查询用户列表通常需要管理员权限 */ GetMapping(/page) public Result getUserPage(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, RequestParam(required false) String username) { PageUser page new Page(pageNum, pageSize); QueryWrapperUser wrapper new QueryWrapper(); if (username ! null !username.trim().isEmpty()) { wrapper.like(username, username); } // 按创建时间倒序 wrapper.orderByDesc(create_time); IPageUser userPage userService.page(page, wrapper); return Result.success(userPage); } }代码关键点解析RestController: 表明这个类是一个控制器并且其方法返回的数据会直接写入 HTTP 响应体通常为 JSON 格式。RequestMapping与PostMapping/GetMapping: 定义了 API 的路径和 HTTP 方法。/user/login对应 POST 请求。Autowired: Spring 的依赖注入注解自动将UserService和JwtUtil的实例注入到控制器中。RequestBody: 表示方法参数应该从 HTTP 请求体中绑定通常用于接收 JSON 格式的请求数据。Valid: 与 JSR-303 验证注解配合使用用于验证传入参数的有效性如非空、邮箱格式等。MyBatis-Plus 分页: 使用Page对象和QueryWrapper可以轻松实现带条件的分页查询这是管理后台的常见需求。统一的响应封装 (Result): 所有接口返回统一格式的 JSON包含状态码、消息和数据。这有利于前端统一处理。5. 前端工程搭建与核心页面开发前端我们使用 Vue3 Vite Element Plus Axios 的技术栈。这是目前构建管理后台非常流行和高效的组合。5.1 创建 Vue3 项目并安装依赖# 使用 Vite 创建 Vue3 TypeScript 项目 npm create vitelatest course-management-frontend -- --template vue-ts cd course-management-frontend # 安装核心依赖 npm install element-plus axios vue-router4 pinia # 安装开发依赖如需要 npm install -D sass unplugin-auto-import unplugin-vue-componentselement-plus: UI 组件库提供丰富的表格、表单、弹窗等组件。axios: HTTP 客户端用于向后端 API 发送请求。vue-router: 前端路由管理器。pinia: Vue3 官方推荐的状态管理库替代 Vuex。5.2 配置 Vite 和 Element Plus 按需导入为了优化打包体积我们配置 Element Plus 的按需自动导入。// 文件路径vite.config.ts import { defineConfig } from vite import vue from vitejs/plugin-vue import AutoImport from unplugin-auto-import/vite import Components from unplugin-vue-components/vite import { ElementPlusResolver } from unplugin-vue-components/resolvers export default defineConfig({ plugins: [ vue(), // 自动导入 Element Plus 组件和相关 API AutoImport({ resolvers: [ElementPlusResolver()], }), Components({ resolvers: [ElementPlusResolver()], }), ], server: { port: 3000, // 前端开发服务器端口 proxy: { // 配置开发服务器代理解决跨域问题 /api: { target: http://localhost:8080, // 后端 API 地址 changeOrigin: true, rewrite: (path) path.replace(/^\/api/, ) // 可选的路径重写 } } } })开发服务器代理 (proxy) 是关键配置。它使得前端在开发时请求/api/user/login会被转发到http://localhost:8080/api/user/login从而绕过浏览器的同源策略限制无需后端配置 CORS生产环境需通过 Nginx 等反向代理解决。5.3 用户登录页面示例我们创建一个简单的登录页面展示 Vue3 的组合式 API 和 Element Plus 组件的使用。!-- 文件路径src/views/LoginView.vue -- template div classlogin-container el-card classlogin-card template #header div classlogin-header课程管理系统 - 登录/div /template el-form :modelloginForm :rulesloginRules refloginFormRef submit.preventhandleLogin el-form-item propusername el-input v-modelloginForm.username placeholder请输入用户名 prefix-iconUser sizelarge / /el-form-item el-form-item proppassword el-input v-modelloginForm.password typepassword placeholder请输入密码 prefix-iconLock sizelarge show-password / /el-form-item el-form-item el-button typeprimary sizelarge :loadingloading clickhandleLogin stylewidth: 100%; {{ loading ? 登录中... : 登录 }} /el-button /el-form-item /el-form div classlogin-footer span还没有账号/span el-link typeprimary clickgoToRegister立即注册/el-link /div /el-card /div /template script setup langts import { ref, reactive } from vue import { useRouter } from vue-router import { ElMessage, type FormInstance, type FormRules } from element-plus import { userLogin } from /api/user // 假设封装好的 API 函数 import { useUserStore } from /stores/user // 使用 Pinia 管理用户状态 const router useRouter() const userStore useUserStore() const loginFormRef refFormInstance() const loading ref(false) const loginForm reactive({ username: , password: }) const loginRules: FormRules { username: [ { required: true, message: 请输入用户名, trigger: blur }, { min: 3, max: 20, message: 长度在 3 到 20 个字符, trigger: blur } ], password: [ { required: true, message: 请输入密码, trigger: blur }, { min: 6, max: 20, message: 长度在 6 到 20 个字符, trigger: blur } ] } const handleLogin async () { // 1. 表单验证 if (!loginFormRef.value) return const valid await loginFormRef.value.validate() if (!valid) return loading.value true try { // 2. 调用登录 API const res await userLogin(loginForm) if (res.code 200) { const { user, token } res.data // 3. 存储用户信息和 Token 到 Pinia 和 localStorage userStore.setUser(user) userStore.setToken(token) localStorage.setItem(token, token) // 持久化存储 // 4. 提示并跳转 ElMessage.success(登录成功) router.push(/dashboard) // 跳转到主页面 } else { ElMessage.error(res.message || 登录失败) } } catch (error) { ElMessage.error(网络请求失败) console.error(error) } finally { loading.value false } } const goToRegister () { router.push(/register) } /script style scoped .login-container { display: flex; justify-content: center; align-items: center; height: 100vh; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); } .login-card { width: 400px; } .login-header { text-align: center; font-size: 1.5rem; font-weight: bold; } .login-footer { text-align: center; margin-top: 20px; font-size: 0.9rem; } /style前端代码关键点script setup: Vue3 的组合式 API 语法糖让逻辑组织更清晰。响应式数据: 使用ref和reactive创建响应式数据。Element Plus 表单验证: 通过:rules属性绑定验证规则validate方法触发验证。Pinia 状态管理: 登录成功后将用户信息和 Token 存储到 Pinia Store 中供全局使用。路由跳转: 使用vue-router的useRouter进行页面导航。API 请求封装:userLogin函数是对axios的封装统一处理请求和响应拦截如自动添加 Token 头、处理错误等。6. 前后端联调与跨域问题解决这是前后端分离开发中最常遇到的“拦路虎”。在开发环境我们通常通过两种方式解决方式一前端配置代理 (推荐)如上文vite.config.ts所示在开发服务器中配置代理将特定前缀的请求转发到后端服务器。这是最安全、最方便的方式前端代码中直接写相对路径/api/xxx即可。方式二后端配置 CORS在后端 SpringBoot 应用中通过一个配置类全局允许跨域请求。// 文件路径src/main/java/com/course/management/config/CorsConfig.java package com.course.management.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; Configuration public class CorsConfig { Bean public CorsFilter corsFilter() { CorsConfiguration config new CorsConfiguration(); // 允许的域不要写*生产环境要指定具体前端地址 config.addAllowedOrigin(http://localhost:3000); // 允许的请求头 config.addAllowedHeader(*); // 允许的请求方法 config.addAllowedMethod(*); // 允许携带凭证如 cookies config.setAllowCredentials(true); // 预检请求的缓存时间秒 config.setMaxAge(3600L); UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); // 对所有接口路径生效 source.registerCorsConfiguration(/**, config); return new CorsFilter(source); } }注意生产环境中addAllowedOrigin应设置为确切的前端部署地址而不是*以增强安全性。联调步骤启动后端 SpringBoot 应用默认端口 8080。启动前端开发服务器默认端口 3000。打开浏览器访问http://localhost:3000。在前端页面进行登录操作浏览器开发者工具的“网络”标签页中应能看到请求被正确发送到http://localhost:8080/api/user/login并收到响应。如果遇到 404 或跨域错误检查代理配置或 CORS 配置是否正确以及后端接口路径是否匹配。7. 数据库操作与 MyBatis-Plus 实战MyBatis-Plus 极大地简化了数据库操作。以下是一个用户服务层和 Mapper 的示例。7.1 实体类 (Entity)// 文件路径src/main/java/com/course/management/entity/User.java package com.course.management.entity; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.time.LocalDateTime; Data TableName(user_info) // 指定对应的数据库表名 public class User { TableId(type IdType.AUTO) // 主键自增 private Long id; private String username; private String password; // 数据库中应存储加密后的密码 private String email; private Integer roleType; // 1-学生2-教师3-管理员 TableField(fill FieldFill.INSERT) // 插入时自动填充 private LocalDateTime registerTime; // 省略 getter/setter由 Data 注解生成 }7.2 Mapper 接口// 文件路径src/main/java/com/course/management/mapper/UserMapper.java package com.course.management.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.course.management.entity.User; import org.apache.ibatis.annotations.Mapper; Mapper // 可被 MapperScan 扫描到 public interface UserMapper extends BaseMapperUser { // 继承 BaseMapper 后即拥有了基本的 CRUD 方法 // 如需复杂查询可在此定义方法并在对应的 XML 文件中编写 SQL User selectByUsername(String username); }对应的 XML 文件如果需要!-- 文件路径src/main/resources/mapper/UserMapper.xml -- ?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.course.management.mapper.UserMapper select idselectByUsername resultTypecom.course.management.entity.User SELECT * FROM user_info WHERE username #{username} /select /mapper7.3 服务层实现// 文件路径src/main/java/com/course/management/service/impl/UserServiceImpl.java package com.course.management.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.course.management.entity.User; import com.course.management.mapper.UserMapper; import com.course.management.service.UserService; import org.springframework.stereotype.Service; import org.springframework.util.DigestUtils; import java.nio.charset.StandardCharsets; Service public class UserServiceImpl extends ServiceImplUserMapper, User implements UserService { Override public User login(String username, String password) { // 1. 根据用户名查询用户 QueryWrapperUser wrapper new QueryWrapper(); wrapper.eq(username, username); User user this.getOne(wrapper); // 2. 用户不存在或密码错误 if (user null) { return null; } // 3. 比较密码这里使用简单的 MD5 加密生产环境应用 BCryptPasswordEncoder String encryptedPassword DigestUtils.md5DigestAsHex(password.getBytes(StandardCharsets.UTF_8)); if (!encryptedPassword.equals(user.getPassword())) { return null; } // 4. 登录成功返回用户信息注意清除密码 user.setPassword(null); return user; } Override public User findByUsername(String username) { QueryWrapperUser wrapper new QueryWrapper(); wrapper.eq(username, username); return this.getOne(wrapper); } }关键点ServiceImplM, T: MyBatis-Plus 提供的通用服务实现类注入了BaseMapper可以直接使用getOne,page,save等方法。密码加密示例中使用了简单的 MD5在生产环境中强烈推荐使用 Spring Security 的BCryptPasswordEncoder它采用加盐哈希更安全。查询构造器QueryWrapper: 提供了链式调用的 API 来构建动态查询条件避免了手写 SQL 字符串拼接。8. 项目部署与上线注意事项当开发完成后你需要将项目部署到服务器上。后端部署打包: 在项目根目录执行mvn clean package -DskipTests会在target目录生成一个可执行的 JAR 文件如course-management-0.0.1-SNAPSHOT.jar。上传: 将 JAR 文件和application-prod.yml生产环境配置文件上传到服务器。运行: 在服务器上使用java -jar course-management-0.0.1-SNAPSHOT.jar --spring.profiles.activeprod命令启动应用。建议使用nohup或 systemd 等服务管理工具来保持进程常驻。前端部署构建: 在前端项目根目录执行npm run build会在dist目录生成静态文件HTML, JS, CSS。上传: 将dist目录下的所有文件上传到 Web 服务器如 Nginx, Apache的静态资源目录。配置 Nginx: 配置 Nginx 将静态文件请求指向dist目录并将/api/开头的请求反向代理到后端 SpringBoot 应用。server { listen 80; server_name your-domain.com; # 你的域名或IP location / { root /path/to/your/frontend/dist; try_files $uri $uri/ /index.html; # 支持 Vue Router 的 history 模式 } location /api/ { proxy_pass http://localhost:8080; # 后端服务地址 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }生产环境关键检查项数据库连接池: 确保使用 HikariCP 等连接池并配置合理的参数。日志: 配置日志级别和输出文件便于排查问题。JVM 参数: 根据服务器内存调整 JVM 堆内存参数如-Xms512m -Xmx1024m。安全:禁用 Swagger 等调试接口。确保密码加密存储。验证 JWT 密钥的强度。配置 HTTPS。备份: 定期备份数据库。9. 常见问题与排查思路在开发和部署过程中你可能会遇到以下典型问题问题现象可能原因排查方式解决方案前端访问后端 API 4041. 后端服务未启动。2. 前端代理或 CORS 配置错误。3. 后端 API 路径与前端请求路径不匹配。1. 检查后端控制台是否启动成功。2. 在浏览器开发者工具“网络”标签查看请求 URL 和响应状态。3. 直接使用 Postman 测试后端接口。1. 确保后端在正确端口运行。2. 核对vite.config.ts的proxy配置或后端的CorsConfig。3. 检查RequestMapping注解的路径。前端控制台报跨域错误后端未正确配置 CORS 或代理未生效。查看浏览器控制台错误信息确认是哪个请求跨域。开发环境优先使用前端代理。生产环境确保 Nginx 配置正确或后端 CORS 配置允许了前端域名。数据库连接失败1. 数据库服务未启动。2.application.yml中数据库连接信息错误。3. 网络或防火墙问题。1. 检查 MySQL 服务状态。2. 核对配置文件中的url,username,password。3. 尝试用命令行工具连接数据库。1. 启动数据库服务。2. 修正配置文件。3. 检查服务器防火墙是否开放了 3306 端口。启动时Mapper扫描失败1.MapperScan注解的包路径错误。2. Mapper 接口上没有加Mapper注解。查看启动日志寻找关于Mapper或Bean创建失败的异常信息。1. 确保MapperScan的包路径包含所有 Mapper 接口。2. 在 Mapper 接口上添加Mapper注解。页面刷新后 404 (Vue Router)Vue Router 使用了history模式但服务器未配置对所有路径返回index.html。直接访问一个前端路由如/dashboard看是否 404。在 Nginx 配置中添加try_files $uri $uri/ /index.html;见上文 Nginx 配置。上传文件失败或大小限制SpringBoot 默认对文件上传大小有限制。查看后端日志是否有MaxUploadSizeExceededException。在application.yml中配置spring.servlet.multipart.max-file-size和max-request-size。掌握这个 SpringBoot Vue3 前后端分离的课程管理系统项目你收获的远不止几行代码。你获得的是一个可复用的现代 Web 应用开发框架理解了从接口设计、数据交互到安全部署的完整流程。下次当你需要开发一个内容管理系统、电商后台或者任何需要权限管理的数据操作平台时这个项目的架构和代码组织方式都可以直接为你所用。真正的学习是把项目中的模式提炼出来应用到下一个场景中。建议你将这个项目作为起点尝试添加新功能如消息通知、文件管理或者将其改造成一个博客系统、工单系统在实践中深化理解。