Spring Boot 3 + Vue 3 + TypeScript 全栈驾校预约系统实战指南
1. 先搞清楚这个项目能解决什么实际问题
如果你正在找一个能跑起来的、前后端分离的、技术栈比较新的实战项目来学习或者作为二次开发的基础,这个基于 Spring Boot 3、Vue 3 和 TypeScript 的驾校预约管理系统,就是一个非常典型的选择。它不是一个简单的增删改查(CRUD)演示,而是围绕一个具体的业务场景——驾校预约——展开的,这意味着你接触到的代码逻辑会更贴近真实生产需求。
这个项目最核心的价值在于,它提供了一个完整的技术栈整合范例。Spring Boot 3 负责后端 API 和业务逻辑,Vue 3 配合 TypeScript 构建现代化的前端界面,两者通过清晰的接口进行通信。对于学习者来说,你能看到从数据库设计、后端接口开发、到前端组件封装、状态管理、路由配置的完整链路。对于有经验的开发者,你可以快速基于这个项目进行改造,应用到其他预约、报名、课程管理等类似场景,因为它已经处理了用户、角色、权限、预约单、教练、车辆等通用模块。
很多人拿到一个项目,第一反应是“跑起来看看”。但我建议你先别急着敲命令,花几分钟理解它的业务边界:它处理学员从选择教练、选择时间段、提交预约,到教练确认、学员取消、管理员排班这一整套流程。理解了业务,再看代码,你才知道每个接口、每个组件、每个状态变更到底在为什么服务。
2. 环境准备:别在第一步就卡住
在开始之前,确保你的本地开发环境满足基本要求。这个项目对环境的版本有一定要求,版本不匹配是导致“跑不起来”最常见的原因。
2.1 后端环境 (Spring Boot 3)
- JDK: 必须是JDK 17 或更高版本。Spring Boot 3 最低要求就是 JDK 17。用
java -version命令检查。如果你还在用 JDK 8,这一步就会直接失败。 - 构建工具: 项目大概率使用 Maven 或 Gradle。查看项目根目录下的
pom.xml或build.gradle文件确认。确保你的 Maven (建议 3.6+) 或 Gradle 已正确安装并配置好镜像源(国内环境推荐配置阿里云镜像,能显著加快依赖下载速度)。 - 数据库: 通常是 MySQL 或 PostgreSQL。查看
application.yml或application.properties配置文件中的spring.datasource配置项。你需要先在本地安装并启动对应的数据库服务,然后根据配置创建好数据库(注意字符集通常设为utf8mb4)。 - IDE: IntelliJ IDEA(社区版或旗舰版)或 Eclipse 均可。IDEA 对 Spring Boot 和 Maven/Gradle 的支持更友好。
2.2 前端环境 (Vue 3 + TypeScript)
- Node.js: 需要Node.js 16.x 或更高版本(建议使用最新的 LTS 版本,如 18.x 或 20.x)。用
node -v和npm -v检查。这是运行 Vue 和打包工具的基础。 - 包管理器: npm 或 yarn。项目通常会在根目录提供
package.json。首次运行npm install或yarn install来安装所有依赖。 - 构建工具: 现代 Vue 3 项目几乎都使用Vite作为构建工具,替代了早期的 Vue CLI。启动命令通常是
npm run dev。 - IDE: Visual Studio Code 是前端开发的首选,配合 Volar 插件(Vue 3 官方推荐)和 TypeScript 插件,能获得最好的开发体验。
关键检查点:在克隆代码后,先别运行。依次核对:
- JDK 版本 >= 17。
- 数据库服务已启动,且库名、用户名、密码与配置文件一致。
- Node.js 版本符合要求。
- 网络通畅,能正常访问 Maven 中央库和 npm registry。
3. 从零启动:后端与前端联调的核心步骤
假设你已经克隆了项目代码,并且环境准备就绪。下面按顺序拆解启动过程。
3.1 后端启动与数据库初始化
- 导入项目:用 IDEA 打开后端项目文件夹(通常是包含
pom.xml的目录)。 - 等待依赖下载:IDE 会自动识别为 Maven/Gradle 项目并开始下载依赖。观察底部的进度条,确保所有依赖下载成功,没有网络超时或版本冲突的红字错误。
- 配置数据库连接:打开
src/main/resources/application.yml,找到数据源配置。将其中的url、username、password修改为你本地数据库的信息。特别注意:url中的数据库名需要提前创建好。spring: datasource: url: jdbc:mysql://localhost:3306/driving_school_db?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: yourpassword driver-class-name: com.mysql.cj.jdbc.Driver - 执行SQL脚本:项目通常会提供一个数据库初始化脚本(如
schema.sql或init.sql),在resources目录下。在你的数据库客户端(如 MySQL Workbench, Navicat)或命令行中,连接到你创建的数据库,然后执行这个 SQL 文件,创建表结构和初始数据(如管理员账号)。 - 启动主类:找到标注了
@SpringBootApplication的主类(通常命名为Application或XXXApplication),右键运行。控制台应输出 Spring Boot 的 Banner,并显示 Tomcat 启动在某个端口(默认 8080),以及数据源连接成功的日志。如果启动失败,最常见的错误是数据库连接不上,请返回检查第3、4步。
3.2 前端启动与代理配置
- 打开前端项目:用 VS Code 打开前端项目文件夹(通常是包含
package.json和vite.config.ts的目录)。 - 安装依赖:在终端中执行
npm install。这个过程可能会因为网络问题较慢,耐心等待完成,确保没有ERR!错误。 - 配置API代理:这是前后端联调的关键。前端开发服务器(如 Vite)运行在一个端口(如 5173),后端运行在另一个端口(如 8080)。为了在开发时避免跨域问题,需要在
vite.config.ts中配置代理,将前端对/api的请求转发到后端。
这样,前端代码中请求// vite.config.ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], server: { proxy: { '/api': { target: 'http://localhost:8080', // 你的后端地址 changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } } })/api/user/login就会被转发到http://localhost:8080/user/login。 - 启动开发服务器:在终端执行
npm run dev。控制台会输出本地访问地址,通常是http://localhost:5173。用浏览器打开这个地址。
3.3 首次登录与功能验证
- 访问登录页:打开前端地址后,你应该能看到登录界面。
- 使用初始账号登录:使用数据库初始化脚本中创建的管理员账号(通常是
admin/admin123或类似)进行登录。 - 导航与功能点验证:登录成功后,逐一点击侧边栏菜单,验证核心功能是否正常:
- 学员管理:能否查看、添加、编辑、禁用学员。
- 教练管理:能否管理教练信息及其可预约时间。
- 车辆管理:能否管理教练车信息。
- 预约管理:核心模块。尝试以管理员身份查看所有预约单,并模拟确认或取消一个预约。尝试以学员身份(如果有测试学员账号)提交一个新的预约。
- 系统管理:查看角色权限、菜单管理、操作日志等。
- 检查网络请求:打开浏览器开发者工具(F12),切换到
Network标签页。进行上述操作时,观察是否有红色的失败请求(4xx, 5xx)。成功的请求状态码应为 200 或 201。点击某个请求,查看Response标签,确认后端返回了正确的 JSON 数据。
如果页面空白或报错:首先检查浏览器控制台(Console)是否有 JavaScript 或 TypeScript 编译错误。常见问题包括依赖缺失、组件导入路径错误、TypeScript 类型错误等。根据错误信息回溯代码。
4. 核心模块与代码结构解析
项目跑通后,我们来深入看几个关键模块的实现,这比单纯看界面更有价值。
4.1 后端:分层架构与接口设计
一个标准的 Spring Boot 项目会采用分层架构:
- Controller 层(
xxxController.java): 接收 HTTP 请求,进行参数校验,调用 Service 层,返回统一格式的 JSON 响应。你会看到大量使用@RestController,@RequestMapping,@PostMapping,@GetMapping等注解。@RestController @RequestMapping("/api/appointment") public class AppointmentController { @Autowired private AppointmentService appointmentService; @PostMapping("/submit") public Result submitAppointment(@RequestBody AppointmentSubmitDTO dto) { // 参数校验 (可以使用 @Validated) // 调用service return appointmentService.submit(dto); } } - Service 层(
xxxService.java及impl目录): 实现核心业务逻辑。例如,在提交预约时,需要检查教练该时间段是否已被预约、学员是否已有未完成的预约等业务规则。 - Mapper/Repository 层: 负责数据库操作。如果使用 MyBatis-Plus,你会看到
XxxMapper.java接口和对应的XxxMapper.xmlSQL 映射文件。如果使用 Spring Data JPA,则是XxxRepository.java接口。 - Entity/DTO/VO:
Entity: 对应数据库表结构(如Appointment.java)。DTO (Data Transfer Object): 用于接口传入传出的数据对象,如AppointmentSubmitDTO,它可能只包含前端提交的几个字段。VO (View Object): 返回给前端的视图对象,可能聚合了多个表的数据。
重点关注:在预约业务中,查看AppointmentService的submit方法,理解其事务 (@Transactional) 管理和业务校验逻辑。
4.2 前端:Vue 3 Composition API 与 TypeScript
现代 Vue 3 项目普遍使用<script setup>语法和 Composition API,代码更简洁。
- 页面组件(
views/目录): 对应一个路由页面,如AppointmentManagement.vue。它通常包含:<script setup lang="ts"> import { ref, onMounted } from 'vue'; import { getAppointmentList } from '@/api/appointment'; // 导入API函数 import type { AppointmentVO } from '@/types/appointment'; // 导入TS类型 // 使用 reactive 或 ref 定义响应式数据 const tableData = ref<AppointmentVO[]>([]); const loading = ref(false); // 生命周期钩子或自定义函数 onMounted(() => { fetchData(); }); const fetchData = async () => { loading.value = true; try { const res = await getAppointmentList(/* 参数 */); tableData.value = res.data; } catch (error) { console.error('获取预约列表失败', error); } finally { loading.value = false; } }; </script> <template> <div> <el-table :data="tableData" v-loading="loading"> <!-- 列定义 --> </el-table> </div> </template> - API 封装(
api/目录): 使用 Axios 封装所有后端接口请求,统一处理请求/响应拦截器、错误处理等。// api/appointment.ts import request from '@/utils/request'; // 这是封装好的axios实例 import type { AppointmentQuery, AppointmentVO } from '@/types/appointment'; export function getAppointmentList(params: AppointmentQuery) { return request.get<ApiResponse<AppointmentVO[]>>('/api/appointment/list', { params }); } - 类型定义(
types/目录): 使用 TypeScript 定义所有接口、DTO、VO 的类型,确保前后端数据契约一致,并获得完美的代码提示和类型安全。// types/appointment.ts export interface AppointmentVO { id: number; studentName: string; coachName: string; carNumber: string; appointmentTime: string; status: 'PENDING' | 'CONFIRMED' | 'CANCELLED' | 'COMPLETED'; } export interface AppointmentQuery { pageNum?: number; pageSize?: number; studentId?: number; status?: string; } - 状态管理: 对于跨组件共享的状态(如用户登录信息),项目可能使用 Pinia(Vue 3 官方推荐的状态管理库)。查看
stores/目录。
重点关注:学习如何将一个复杂的预约管理页面拆分成多个可复用的子组件(如搜索表单SearchForm.vue、预约表格AppointmentTable.vue、预约表单弹窗AppointmentDialog.vue),以及它们之间如何通过props和emit通信。
5. 常见问题排查与进阶调整
即使按照步骤操作,你也可能会遇到一些问题。下面是一个排查顺序:
后端启动失败,端口被占用:
- 现象:
Web server failed to start. Port 8080 was already in use. - 解决:修改
application.yml中的server.port为其他端口(如 8081),或者找到占用 8080 端口的进程并结束它(命令:netstat -ano | findstr :8080,然后taskkill /PID <进程号> /F)。
- 现象:
前端编译报 TypeScript 错误:
- 现象:
npm run dev失败,控制台提示TS2307: Cannot find module '@/...'或类型不匹配。 - 解决:
- 检查
tsconfig.json中的paths配置,确保@/*正确指向src/*。 - 检查导入语句的路径和文件名大小写是否正确(Linux 系统区分大小写)。
- 如果是第三方库类型缺失,尝试安装
@types/xxx或检查package.json中依赖版本。
- 检查
- 现象:
前端页面能打开,但接口请求 404:
- 现象:浏览器 Network 中看到对
/api/xxx的请求返回 404。 - 解决:
- 首先确认后端服务是否真的在运行(访问
http://localhost:8080看是否有响应)。 - 检查
vite.config.ts中的proxy配置,target地址和端口是否正确。 - 检查后端
Controller上的@RequestMapping路径是否匹配。前端请求/api/appointment/list,后端可能是@GetMapping("/list")在类级别的@RequestMapping("/appointment")下。
- 首先确认后端服务是否真的在运行(访问
- 现象:浏览器 Network 中看到对
登录成功但跳转后菜单不显示或权限错误:
- 现象:登录后页面空白或侧边栏只有部分菜单。
- 解决:这通常与动态路由和权限验证有关。检查:
- 登录接口返回的菜单数据格式是否与前端
router配置期望的格式一致。 - 前端是否根据用户角色(
roles)过滤了菜单。查看permission.ts或路由守卫逻辑。 - 浏览器
Application->Local Storage中,存储的 token 和用户信息是否正确。
- 登录接口返回的菜单数据格式是否与前端
预约业务逻辑出错:
- 现象:提交预约时提示“时间冲突”或“教练不可用”,但你觉得数据没问题。
- 解决:这是最好的学习机会。不要只看前端提示,打开浏览器开发者工具的 Network,查看失败请求的完整
Response信息,后端通常会返回更详细的错误原因。然后去后端对应的Service方法中,查看具体的校验逻辑,可能涉及到数据库查询的时间范围判断、状态判断等。通过打断点或添加日志来调试。
进阶调整建议:
- 更换数据库:如果想从 MySQL 换成 PostgreSQL,只需修改
pom.xml中的依赖和application.yml中的driver-class-name及url。 - 调整鉴权方式:项目可能使用 JWT (JSON Web Token) 或 Session。如果想深入了解,查看登录接口的返回和后续请求的
Header(通常有一个Authorization: Bearer xxx或Cookie)。相关的过滤器/拦截器代码在config或filter包下。 - 部署尝试:学习如何将前后端分别打包。后端使用
mvn clean package生成jar包,用java -jar运行。前端使用npm run build生成静态文件,可以放到 Nginx 或 Spring Boot 的static目录下。
这个项目的价值在于它提供了一个全栈的、有业务深度的脚手架。不要满足于仅仅“跑起来”,多去触发各种操作,观察网络请求,阅读关键业务代码,并尝试修改一些逻辑(比如增加一个预约状态),这才是从项目学习中提升能力的正确方式。